#include "ukui-wayland-client.h"

#include <wayland-client-core.h>

namespace ukuiwaylandclient
{

// class wl_display
wl_display_t::wl_display_t(int fd)
    : m_wl_display(wl_display_connect_to_fd(fd))
{
}

wl_display_t::wl_display_t(const char *name)
    : m_wl_display(wl_display_connect(name))
{
}

wl_display_t::wl_display_t(struct ::wl_display *obj)
    : m_wl_display(obj)
{
}

wl_display_t::~wl_display_t()
{
    wl_display_disconnect(m_wl_display);
    m_wl_display = nullptr;
}

const struct wl_interface *wl_display_t::interface()
{
    return &::wl_display_interface;
}

int wl_display_t::get_fd() const
{
    return wl_display_get_fd(m_wl_display);
}

int wl_display_t::dispatch() const
{
    return wl_display_dispatch(m_wl_display);
}

int wl_display_t::dispatch_queue(wl_event_queue_t *queue) const
{
    if (!queue) {
        return -1; // Invalid queue
    }
    return wl_display_dispatch_queue(m_wl_display, queue->m_wl_event_queue);
}

int wl_display_t::dispatch_queue_pending(wl_event_queue_t *queue) const
{
    if (!queue) {
        return -1; // Invalid queue
    }
    return wl_display_dispatch_queue_pending(m_wl_display, queue->m_wl_event_queue);
}

int wl_display_t::dispatch_pending() const
{
    return wl_display_dispatch_pending(m_wl_display);
}

wl_display_t::error wl_display_t::get_error() const
{
    return (wl_display_t::error)wl_display_get_error(m_wl_display);
}

int wl_display_t::flush() const
{
    return wl_display_flush(m_wl_display);
}

int wl_display_t::roundtrip_queue(wl_event_queue_t *queue) const
{
    if (!queue) {
        return -1; // Invalid queue
    }
    return wl_display_roundtrip_queue(m_wl_display, queue->m_wl_event_queue);
}

int wl_display_t::roundtrip() const
{
    return wl_display_roundtrip(m_wl_display);
}

wl_event_queue_t *wl_display_t::create_queue() const
{
    struct ::wl_event_queue *queue = wl_display_create_queue(m_wl_display);
    if (!queue) {
        return nullptr; // Failed to create queue
    }
    return new wl_event_queue_t(queue);
}

#if WAYLAND_VERSION_NUM >= WAYLAND_VERSION_NUM_1_23_0
wl_event_queue_t *wl_display_t::create_queue_with_name(const char *name) const
{
    struct ::wl_event_queue *queue = wl_display_create_queue_with_name(m_wl_display, name);
    if (!queue) {
        return nullptr; // Failed to create queue
    }

    return new wl_event_queue_t(queue);
}
#endif

int wl_display_t::prepare_read_queue(struct wl_event_queue *queue)
{
    if (!queue) {
        return -1; // Invalid queue
    }
    return wl_display_prepare_read_queue(m_wl_display, queue);
}

int wl_display_t::prepare_read()
{
    return wl_display_prepare_read(m_wl_display);
}

void wl_display_t::cancel_read()
{
    wl_display_cancel_read(m_wl_display);
}

int wl_display_t::read_events()
{
    return wl_display_read_events(m_wl_display);
}

void wl_display_t::set_log_handler(wl_log_func_t handler)
{
    wl_log_set_handler_client(handler);
}

#if WAYLAND_VERSION_NUM >= WAYLAND_VERSION_NUM_1_23_0
void wl_display_t::set_max_buffer_size(size_t max_buffer_size)
{
    wl_display_set_max_buffer_size(m_wl_display, max_buffer_size);
}
#endif

wl_callback_t *wl_display_t::sync()
{
    struct ::wl_callback *callback = wl_display_sync(m_wl_display);
    if (!callback) {
        return nullptr; // Failed to create sync callback
    }
    return new wl_callback_t(callback);
}

wl_registry_t *wl_display_t::get_registry()
{
    struct ::wl_registry *registry = wl_display_get_registry(m_wl_display);
    if (!registry) {
        return nullptr; // Failed to get registry
    }
    return new wl_registry_t(registry);
}

// class wl_event_queue
wl_event_queue_t::wl_event_queue_t(struct ::wl_event_queue *obj)
    : m_wl_event_queue(obj)
{
}

wl_event_queue_t::~wl_event_queue_t()
{
    if (m_wl_event_queue)
        wl_event_queue_destroy(m_wl_event_queue);

    m_wl_event_queue = nullptr;
}

#if WAYLAND_VERSION_NUM >= WAYLAND_VERSION_NUM_1_23_0
const char *wl_event_queue_t::get_name() const
{
    return wl_event_queue_get_name(m_wl_event_queue);
}
#endif

} // namespace ukui::wayland::client